package com.yami.shop.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yami.shop.bean.app.param.OrderRefundParam;
import com.yami.shop.bean.enums.*;
import com.yami.shop.bean.event.*;
import com.yami.shop.bean.model.*;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.util.Arith;
import com.yami.shop.dao.ActivityReceiveRecordMapper;
import com.yami.shop.dao.ProdExtensionMapper;
import com.yami.shop.dao.SkuStockLockMapper;
import com.yami.shop.dao.SkuStockMapper;
import com.yami.shop.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component("businessNftResultFailListener")
@AllArgsConstructor
public class BusinessNftResultFailListener {

    private final ProductService productService;

    private final OrderService orderService;

    private final OrderItemService orderItemService;

    private final OrderRefundService orderRefundService;

    private final UserAirdropService userAirdropService;

    private final BusinessNftService businessNftService;

    private final BusinessNftRecordService businessNftRecordService;

    private final AirdropTaskService airdropTaskService;

    private final ApplicationEventPublisher eventPublisher;

    private final SkuService skuService;

    private final Snowflake snowflake;

    private final SkuStockMapper skuStockMapper;

    private final ActivityReceiveRecordMapper activityReceiveRecordMapper;

    private final SkuStockLockService skuStockLockService;

    private final ProdExtensionMapper prodExtensionMapper;

    private final ProdExtensionService prodExtensionService;

    private final SkuStockLockMapper skuStockLockMapper;

    /**
     * 空投商品
     *
     * @param event event
     */
    @EventListener(BusinessNftResultFailEvent.class)
    @Transactional(rollbackFor = Exception.class)
    public void businessNftResultFailListener(BusinessNftResultFailEvent event) {
        if (ObjectUtil.isEmpty(event.getOutId())) {
            return;
        }
        // 获取取币业务信息
        BusinessNft businessNft = businessNftService.getOne(new LambdaQueryWrapper<BusinessNft>().eq(BusinessNft::getOutId, event.getOutId()).eq(BusinessNft::getBusinessNftId, event.getBusinessNftId()));
        if (ObjectUtil.isEmpty(businessNft)) {
            return;
        }
        // 查询取币成功的数据
        Long count = businessNftRecordService.count(new LambdaQueryWrapper<BusinessNftRecord>().eq(BusinessNftRecord::getBusinessNftId, businessNft.getBusinessNftId()).eq(BusinessNftRecord::getStatus, 2));
        switch (businessNft.getBusinessType()) {
            // 订单取币业务
            case 0:
                // 创建退款申请
                Order order = orderService.getById(event.getOutId());
                if (Objects.equals(order.getIsRefund(), 0)) {
                    // 当前订单不能退款，请联系客服
                    throw new YamiShopBindException(I18nMessage.getMessage("yami.order.virtual.refund.check1"));
                }
                boolean isOrderStatus = Objects.equals(order.getStatus(), OrderStatus.CONSIGNMENT.value()) || Objects.equals(order.getStatus(), OrderStatus.SUCCESS.value());
                OrderRefundParam orderRefundParam = new OrderRefundParam();
                orderRefundParam.setRefundAmount(order.getActualTotal());
                orderRefundParam.setRefundType(1);
                checkAndGetOrderStatus(orderRefundParam, order, isOrderStatus);
                // 生成退款单信息
                OrderRefund newOrderRefund = new OrderRefund();

                // 获取所有正在进行中的退款订单
                List<OrderRefund> orderRefunds = orderRefundService.getProcessingOrderRefundByOrderId(order.getOrderId());

                for (OrderRefund orderRefund : orderRefunds) {
                    if (Objects.equals(RefundType.ALL.value(), orderRefund.getRefundType())) {
                        // 该订单正在进行整单退款，无法进行新的退款操作
                        throw new YamiShopBindException("yami.order.all.refund.check");
                    }
                }
                // 如果存在分销订单，则计算分销总金额
                List<OrderItem> orderItemList = orderItemService.getUnGiveawayOrderItemsByOrderNumber(order.getOrderNumber());
                // 获取所有的订单项总数
                long orderItemCount = orderItemService.count(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, order.getOrderNumber()).isNull(OrderItem::getGiveawayOrderItemId));
                // 全部物品退款 退款单类型（1:整单退款,2:单个物品退款）
                // 计算该订单项的分销金额
                newOrderRefund.setDistributionTotalAmount(orderService.sumTotalDistributionAmountByOrderItem(orderItemList));
                // 计算平台退款金额（退款时将这部分钱退回给平台，所以商家要扣除从平台这里获取的金额）
                newOrderRefund.setPlatformRefundAmount(order.getPlatformAmount());
                newOrderRefund.setPlatformRefundCommission(order.getPlatformCommission());

                newOrderRefund.setShopId(order.getShopId());
                newOrderRefund.setUserId(order.getUserId());
                newOrderRefund.setOrderId(order.getOrderId());
                newOrderRefund.setRefundSn(String.valueOf(snowflake.nextId()));
                newOrderRefund.setRefundType(1);

                newOrderRefund.setRefundAmount(order.getActualTotal());
                newOrderRefund.setOrderItemId(0L);
                // 如果是整单退款，则最大退款金额就为退款金额
                newOrderRefund.setMaxRefundAmount(newOrderRefund.getRefundAmount());
                newOrderRefund.setRefundActualTotal(order.getActualTotal());
                newOrderRefund.setGoodsNum(0);
                newOrderRefund.setApplyType(1);
                newOrderRefund.setIsReceiver(false);
                newOrderRefund.setBuyerReason(event.getReason());
                newOrderRefund.setReturnMoneySts(ReturnMoneyStsType.APPLY.value());
                newOrderRefund.setApplyTime(new Date());
                newOrderRefund.setUpdateTime(new Date());
                orderRefundService.applyRefund(newOrderRefund);
                break;
            // 开盲取币业务
            case 1:
                eventPublisher.publishEvent(new OpenBoxFailEvent(Long.valueOf(businessNft.getOutId()), Long.valueOf(businessNft.getProdId()), businessNft.getUserId()));
                break;
            // 合成取币业务
            case 2:

                break;
            // 零元购
            case 4:
                ActivityReceiveRecord activityReceiveRecord = activityReceiveRecordMapper.selectById(Long.valueOf(event.getOutId()));
                activityReceiveRecord.setStatus(2);
                activityReceiveRecord.setUpdateTime(new Date());
                activityReceiveRecord.setReason(event.getReason());
                activityReceiveRecordMapper.updateById(activityReceiveRecord);
                // 解锁库存
                unlockStock(event);
                break;
            //提现空投
            case 5:
                break;
            // 空投取币业务
            case 9:
                // 修改空投记录状态
                UserAirdrop userAirdrop = new UserAirdrop();
                userAirdrop.setAirDropId(Long.valueOf(event.getOutId()));
                userAirdrop.setSuccessNum(count.intValue());
                userAirdrop.setStatus(count.intValue() == businessNft.getNum() ? 2 : 3);
                if (count.intValue() == 0) {
                    userAirdrop.setStatus(1);
                }
                userAirdrop.setReason(getString(event.getReason()));
                userAirdrop.setUpdateTime(new Date());
                userAirdropService.updateById(userAirdrop);
                List<Sku> skus = skuService.listSkuByProdId(Long.valueOf(businessNft.getProdId()));
                // 更新sku库存
                Sku sku = skus.get(0);
                sku.setStocks(count.intValue());
                skuStockMapper.updateStocks(sku);
                skuService.removeSkuCacheBySkuId(sku.getSkuId(), sku.getProdId());
                productService.removeProdCacheByProdId(sku.getProdId());
                // 更新es中的商品库存
                eventPublisher.publishEvent(new EsProductUpdateEvent(sku.getProdId(), null, EsOperationType.UPDATE));
                UserAirdrop userAirdropServiceById = userAirdropService.getById(Long.valueOf(event.getOutId()));
                // 任务空投
                if (ObjectUtil.isNotEmpty(userAirdropServiceById) && userAirdropServiceById.getBusinessType() == 2 && ObjectUtil.isNotNull(userAirdropServiceById.getAirdropBusinessId())) {
                    AirdropTask airdropTask = new AirdropTask();
                    airdropTask.setSuccessNum(count.intValue());
                    airdropTask.setUpdateTime(new Date());
                    airdropTask.setReason(event.getReason());
                    airdropTaskService.updateById(airdropTask);
                }
                // 空投权益券系统自动空投完成失败之后通知权益服务处理权益券状态
                if (ObjectUtil.isNotEmpty(userAirdropServiceById) && userAirdropServiceById.getBusinessType() == 3 && ObjectUtil.isNotNull(userAirdropServiceById.getAirdropBusinessId())) {
                    eventPublisher.publishEvent(new KtVerificationRightsEvent(1L,userAirdropServiceById.getAirdropBusinessId()));
                }
                // 空投邀请、拉新奖励失败后通知上游服务，修改奖励发放状态
                if (ObjectUtil.isNotEmpty(userAirdropServiceById) && userAirdropServiceById.getBusinessType() == 4 && ObjectUtil.isNotNull(userAirdropServiceById.getAirdropBusinessId())) {
                    eventPublisher.publishEvent(new GrantEvent(userAirdropServiceById.getAirdropBusinessId(),2));
                }
                break;
            case 10:
                break;
            case 11:
                break;
            default:
        }
    }

    private void unlockStock(BusinessNftResultFailEvent event) {
        List<SkuStockLock> allSkuWithStocks = skuStockLockService.list(new LambdaQueryWrapper<SkuStockLock>().in(SkuStockLock::getOrderNumber, event.getOutId()).eq(SkuStockLock::getStatus, 0));
        if (CollectionUtil.isEmpty(allSkuWithStocks)) {
            return;
        }
        List<Long> lockIds = allSkuWithStocks.stream().map(SkuStockLock::getId).collect(Collectors.toList());
        List<Long> prodIds = allSkuWithStocks.stream().map(SkuStockLock::getProdId).collect(Collectors.toList());

        // 还原商品库存
        prodExtensionMapper.addStockByOrder(allSkuWithStocks);
        // 还原sku库存
        skuStockMapper.addStockByOrder(allSkuWithStocks);
        // 将锁定状态标记为已解锁
        int updateStatus = skuStockLockMapper.unLockByIds(lockIds);
        for (SkuStockLock allSkuWithStock : allSkuWithStocks) {
            skuService.removeSkuStockCache(allSkuWithStock.getSkuId(), allSkuWithStock.getProdId());
            prodExtensionService.removeProdExtensionCache(allSkuWithStock.getProdId());
        }
        // 更新es中的商品库存
        try {
            eventPublisher.publishEvent(new EsProductUpdateEvent(null, new ArrayList<>(prodIds), EsOperationType.UPDATE_SOLD_NUM_BATCH));
        } catch (Exception e) {
            log.error("更新es商品库存失败，错误为：{}", e);
        }
    }

    private void checkAndGetOrderStatus(OrderRefundParam orderRefundParam, Order order, boolean isOrderStatus) {
        if (!Objects.equals(order.getIsPayed(), 1)) {
            // 当前订单还未付款，无法申请
            throw new YamiShopBindException("yami.order.not.paid");
        }

        if (Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
            // 当前订单已失败，不允许退款
            throw new YamiShopBindException("yami.order.has.failed");
        }

        if (Objects.equals(order.getStatus(), OrderStatus.WAIT_GROUP.value())) {
            // 当前订单正在等待成团状态，需等待成团才能进行下一步操作
            throw new YamiShopBindException("yami.group.user.join.check");
        }

        if (orderRefundParam.getRefundAmount() > order.getActualTotal()) {
            // 退款金额已超出订单金额，无法申请
            throw new YamiShopBindException("yami.refund.exceeded.amount");
        }
        // 待收货或者确认收货 -> 整单退款 -> 退款金额 < 订单金额 - 运费金额
        if (isOrderStatus && orderRefundParam.getRefundType().equals(RefundType.ALL.value())) {
            // 订单可退款金额 = 订单实际金额 - （订单运费金额 - 平台免运费金额）
            Double refundAmount = Arith.sub(order.getActualTotal(), Arith.sub(order.getFreightAmount(), order.getPlatformFreeFreightAmount()));
            if (orderRefundParam.getRefundAmount() > refundAmount) {
                // 退款金额已超出订单金额，无法申请
                throw new YamiShopBindException("yami.refund.exceeded.amount");
            }
        }

        if (!orderRefundService.checkRefundDate(order)) {
            // 该商品已经确认收货超过x天
            String dayMsg = I18nMessage.getMessage("yami.order.refund.day.check");
            String dayMsg2 = I18nMessage.getMessage("yami.order.refund.day.check2");
            throw new YamiShopBindException(dayMsg + Constant.MAX_FINALLY_REFUND_TIME + dayMsg2);
        }
        if (Objects.equals(order.getOrderType(), Constant.ORDER_TYPE_SCORE)) {
            // 积分商品，无法退款
            throw new YamiShopBindException("yami.order.refund.score");
        }
        boolean inRefund = !Objects.isNull(order.getRefundStatus()) && !Objects.equals(order.getRefundStatus(), RefundStatusEnum.DISAGREE.value());
        if (Objects.equals(orderRefundParam.getRefundType(), RefundType.ALL.value()) && inRefund) {
            // 该订单已有商品正在退款中，不能再进行整单退款
            throw new YamiShopBindException("yami.order.refund.go.on");
        }
    }

    private String getString(String e) {
        String msg = "";
        if(StrUtil.isEmpty(e)){
            msg ="null--";
        }else if(e.length()>500){
            msg = e.substring(0,500);
        }else{
            msg = e;
        }
        return msg;
    }
}
